﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;

namespace ImageResizer
{
    class Program
    {
        static void Main(string[] args)
        {
            string ResizeDirectoryName;
            int ResizedWidth;

            int ImageCount = 0;

            if (args.Length == 2)
            {
                ResizeDirectoryName = args[0];
                ResizedWidth = Convert.ToInt32(args[1]);
            }
            else
            {
                Console.WriteLine("Usage: ImageResizer.exe DestinationDirectoryName NewWidth");
                Console.ReadKey(true);
                return;
            }

            try
            {
                string StartupPath =
                    System.IO.Path.GetDirectoryName(Assembly.GetEntryAssembly().Location);

                if (!Directory.Exists(StartupPath))
                {
                    // ERROR
                    throw new Exception("StartupPath does not exist...");
                }

                string ResizePath = StartupPath + @"\" + ResizeDirectoryName;
                if (!Directory.Exists(ResizePath))
                {
                    Directory.CreateDirectory(ResizePath);
                }

                foreach (string item in Directory.EnumerateFiles(StartupPath, "*.jpg"))
                {
                    Image tempImage = Image.FromFile(item);
                    Bitmap resizedImage = resizeImageByWidth(tempImage, ResizedWidth);
                    
                    //resizedImage = Sharpen(resizedImage);

                    string newPath = ResizePath + @"\" + Path.GetFileName(item);
                    
                    //resizedImage.Save(newPath);
                    saveJpeg(newPath, resizedImage, 100);

                    ImageCount++;
                }
            }
            catch (Exception exc)
            {
                Console.WriteLine("There was an error: " + exc.Message);
                Console.ReadKey(true);
                return;
            }

            Console.WriteLine("Successfully resized " + ImageCount + " images.");
            //Console.ReadKey(true);
        }

        private static Bitmap resizeImageByWidth(Image imgToResize, int Width)
        {
            int sourceWidth = imgToResize.Width;
            int sourceHeight = imgToResize.Height;

            float nPercent = 0;

            nPercent = ((float)Width / (float)sourceWidth);

            int destWidth = Width;
            int destHeight = (int)(sourceHeight * nPercent);

            Bitmap b = new Bitmap(destWidth, destHeight);
            Graphics g = Graphics.FromImage((Image)b);
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

            g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
            g.Dispose();

            return b;
        }

        private static Bitmap resizeImageByHeight(Image imgToResize, int Height)
        {
            int sourceWidth = imgToResize.Width;
            int sourceHeight = imgToResize.Height;

            float nPercent = 0;

            nPercent = ((float)Height / (float)sourceHeight);

            int destHeight = Height;
            int destWidth = (int)(sourceWidth * nPercent);

            Bitmap b = new Bitmap(destWidth, destHeight);
            Graphics g = Graphics.FromImage((Image)b);
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic;

            g.DrawImage(imgToResize, 0, 0, destWidth, destHeight);
            g.Dispose();

            return b;
        }

        private static void saveJpeg(string path, Bitmap img, long quality)
        {
            // Encoder parameter for image quality
            EncoderParameter qualityParam = new EncoderParameter(System.Drawing.Imaging.Encoder.Quality, quality);

            // Jpeg image codec
            ImageCodecInfo jpegCodec = getEncoderInfo("image/jpeg");

            if (jpegCodec == null)
                return;

            EncoderParameters encoderParams = new EncoderParameters(1);
            encoderParams.Param[0] = qualityParam;

            img.Save(path, jpegCodec, encoderParams);
        }

        private static ImageCodecInfo getEncoderInfo(string mimeType)
        {
            // Get image codecs for all image formats
            ImageCodecInfo[] codecs = ImageCodecInfo.GetImageEncoders();

            // Find the correct image codec
            for (int i = 0; i < codecs.Length; i++)
                if (codecs[i].MimeType == mimeType)
                    return codecs[i];
            return null;
        }

        public static Bitmap Sharpen(Bitmap image)
        {
            Bitmap sharpenImage = (Bitmap)image.Clone();

            const int filterWidth = 3;
            const int filterHeight = 3;

            const double a = -1;
            double[,] filter = new double[filterWidth, filterHeight] {
                { a,  a,  a },
                { a,  25,  a },
                { a,  a,  a }
            };

            double factor = 1.0 / 16;

            //int filterWidth = 3;
            //int filterHeight = 3;
            //double[,] filter = new double[filterWidth, filterHeight];
            //filter[0, 0] = filter[0, 1] = filter[0, 2] = filter[1, 0] = filter[1, 2] = filter[2, 0] = filter[2, 1] = filter[2, 2] = -1;
            //filter[1, 1] = 9;
            //double factor = 1.0;

            int width = image.Width;
            int height = image.Height;

            // Create sharpening filter.
            double bias = 0.0;

            Color[,] result = new Color[image.Width, image.Height];

            // Lock image bits for read/write.
            BitmapData pbits = sharpenImage.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

            // Declare an array to hold the bytes of the bitmap.
            int bytes = pbits.Stride * height;
            byte[] rgbValues = new byte[bytes];

            // Copy the RGB values into the array.
            System.Runtime.InteropServices.Marshal.Copy(pbits.Scan0, rgbValues, 0, bytes);

            int rgb;
            // Fill the color array with the new sharpened color values.
            for (int x = 0; x < width; ++x)
            {
                for (int y = 0; y < height; ++y)
                {
                    double red = 0.0, green = 0.0, blue = 0.0;

                    for (int filterX = 0; filterX < filterWidth; filterX++)
                    {
                        for (int filterY = 0; filterY < filterHeight; filterY++)
                        {
                            int imageX = (x - filterWidth / 2 + filterX + width) % width;
                            int imageY = (y - filterHeight / 2 + filterY + height) % height;

                            rgb = imageY * pbits.Stride + 3 * imageX;

                            red += rgbValues[rgb + 2] * filter[filterX, filterY];
                            green += rgbValues[rgb + 1] * filter[filterX, filterY];
                            blue += rgbValues[rgb + 0] * filter[filterX, filterY];
                        }
                        int r = Math.Min(Math.Max((int)(factor * red + bias), 0), 255);
                        int g = Math.Min(Math.Max((int)(factor * green + bias), 0), 255);
                        int b = Math.Min(Math.Max((int)(factor * blue + bias), 0), 255);

                        result[x, y] = Color.FromArgb(r, g, b);
                    }
                }
            }

            // Update the image with the sharpened pixels.
            for (int x = 0; x < width; ++x)
            {
                for (int y = 0; y < height; ++y)
                {
                    rgb = y * pbits.Stride + 3 * x;

                    rgbValues[rgb + 2] = result[x, y].R;
                    rgbValues[rgb + 1] = result[x, y].G;
                    rgbValues[rgb + 0] = result[x, y].B;
                }
            }

            // Copy the RGB values back to the bitmap.
            System.Runtime.InteropServices.Marshal.Copy(rgbValues, 0, pbits.Scan0, bytes);
            // Release image bits.
            sharpenImage.UnlockBits(pbits);

            return sharpenImage;
        }
    }
}
